#include "Render.h"

#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QMatrix4x4>
#include <QOpenGLTexture>
#include <QOpenGLVertexArrayObject>
#include <QSequentialAnimationGroup>
#include <QPropertyAnimation>
#include <QOpenGLExtraFunctions>
#include <QTimer>
#include <QList>
#include <QVector3D>
#include "Common.h"
Render::Render() {
}
Render::~Render() {
}

void Render::init(Scene* scene) {
	this->scene = scene;
	QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();
	program->addShaderFromSourceFile(QOpenGLShader::Vertex, currentPathFile("Graphics/2D/shaders/basic.vert"));
	program->addShaderFromSourceFile(QOpenGLShader::Fragment, currentPathFile("Graphics/2D/shaders/basic.frag"));
	program->link();
	vao = new QOpenGLVertexArrayObject;
	if (vao->create())
		vao->bind();
	this->program->bind();
	QSet<Shape*>::const_iterator indexShape;
	for (indexShape = this->scene->getMeshs()->constBegin(); indexShape != this->scene->getMeshs()->constEnd(); ++indexShape) {
		Shape* shape = (*indexShape);
		shape->vbo->create();
	}
	this->scene->reszie(this->width, this->height);
	this->modelLocation = program->uniformLocation("modelMatrix");
	this->cameraLocation = program->uniformLocation("cameraMatrix");
	this->colorLocation = program->uniformLocation("color");

	QMatrix4x4* camera = new QMatrix4x4();
	camera->Identity();
	camera->ortho(-width / 2, width / 2, -height / 2, height / 2, -1, 1);
	this->program->setUniformValue(cameraLocation, *camera);

	f->glEnable(GL_LINE_SMOOTH);
	f->glEnable(GL_BLEND);
	f->glEnable(GL_DEPTH_TEST);
	f->glEnable(GL_CULL_FACE);
	f->glDisable(GL_BLEND);
}

void Render::render() {
	this->program->bind();
	QOpenGLExtraFunctions* f = QOpenGLContext::currentContext()->extraFunctions();
	f->glClearColor(0, 0, 0, 1);
	f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	if (derty) {
		derty = false;
		QMatrix4x4* camera = new QMatrix4x4();
		camera->Identity();
		camera->ortho(-width / 2, width / 2, -height / 2, height / 2, -1, 1);
		this->program->setUniformValue(cameraLocation, *camera);
	}
	this->scene->createVertex();
	QSet<Shape*>::const_iterator i;
	for (i = this->scene->getMeshs()->constBegin(); i != this->scene->getMeshs()->constEnd(); ++i) {
		Shape* shape = (*i);
		if (dynamic_cast<RectangleShape*>(shape)) {
			RectangleShape* rectangle = (RectangleShape*)shape;
			QMatrix4x4 modelMatrix;
			modelMatrix.Identity();
			modelMatrix.translate(rectangle->getPosition()->x(), rectangle->getPosition()->y());
			modelMatrix.rotate(rectangle->getAngle(), QVector3D(0, 0, 1));
			rectangle->vbo->bind();
			rectangle->vbo->allocate(rectangle->getVertex(), rectangle->getVertexSize() * sizeof(GLfloat));
			this->program->setUniformValue(modelLocation, modelMatrix);
			this->program->setUniformValue(colorLocation,*rectangle->getColor());

			f->glEnableVertexAttribArray(0);
			f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
			f->glDrawArrays(GL_TRIANGLES, 0, rectangle->getVertexSize() / 2);
			rectangle->vbo->release();
		}
		else if (dynamic_cast<CircleShape*>(shape)) {
			CircleShape* circleShape = (CircleShape*)shape;
			QMatrix4x4 modelMatrix;
			modelMatrix.Identity();
			modelMatrix.translate(circleShape->getPosition()->x(), circleShape->getPosition()->y());
			modelMatrix.rotate(circleShape->getAngle(), QVector3D(0, 0, 1));
			circleShape->vbo->bind();
			circleShape->vbo->allocate(circleShape->getVertex(), circleShape->getVertexSize() * sizeof(GLfloat));
			this->program->setUniformValue(modelLocation, modelMatrix);
			this->program->setUniformValue(colorLocation, *circleShape->getColor());

			f->glEnableVertexAttribArray(0);
			f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
			f->glDrawArrays(GL_TRIANGLES, 0, circleShape->getVertexSize() / 2);
			circleShape->vbo->release();
		}
		else if (dynamic_cast<TriangleShape*>(shape)) {
			TriangleShape* triangleShape = (TriangleShape*)shape;
			QMatrix4x4 modelMatrix;
			modelMatrix.Identity();
			modelMatrix.translate(triangleShape->getPosition()->x(), triangleShape->getPosition()->y());
			modelMatrix.rotate(triangleShape->getAngle(), QVector3D(0, 0, 1));
			triangleShape->vbo->bind();
			triangleShape->vbo->allocate(triangleShape->getVertex(), triangleShape->getVertexSize() * sizeof(GLfloat));
			this->program->setUniformValue(modelLocation, modelMatrix);
			this->program->setUniformValue(colorLocation, *triangleShape->getColor());

			f->glEnableVertexAttribArray(0);
			f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
			f->glDrawArrays(GL_TRIANGLES, 0, triangleShape->getVertexSize() / 2);
			triangleShape->vbo->release();
		}
	}
	this->program->release();
}

void Render::resize(int w, int h) {
	this->width = w;
	this->height = h;
	this->derty = true;
}
